	package org.eesgmbh.gimv.samples.openstreetmap.client;

import org.eesgmbh.gimv.client.event.LoadImageDataEvent;
import org.eesgmbh.gimv.client.event.LoadImageDataEventHandler;
import org.eesgmbh.gimv.client.event.SetDomainBoundsEvent;
import org.eesgmbh.gimv.client.event.SetDomainBoundsEventHandler;
import org.eesgmbh.gimv.client.event.SetImageUrlEvent;
import org.eesgmbh.gimv.client.event.SetMaxDomainBoundsEvent;
import org.eesgmbh.gimv.client.event.SetOverviewDomainBoundsEvent;
import org.eesgmbh.gimv.client.event.SetOverviewDomainBoundsEventHandler;
import org.eesgmbh.gimv.client.event.SetViewportPixelBoundsEvent;
import org.eesgmbh.gimv.client.history.DefaultSetDomainBoundsEventHistoryTokenTransformer;
import org.eesgmbh.gimv.client.history.UnparsableHistoryTokenException;
import org.eesgmbh.gimv.client.widgets.Viewport;
import org.eesgmbh.gimv.shared.util.Bounds;

import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerManager;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;

/**
 *
 * @author Christian Seewald - EES GmbH - c.seewald@ees-gmbh.de
 *
 */
public class OpenStreetMapSampleController {

	private final Viewport primaryViewport;
	private final Viewport overviewViewport;

	private final HandlerManager primaryHandlerManager;
	private final HandlerManager overviewHandlerManager;

	private final PrimaryAppEventBroker primaryEventBroker;
	private OverviewAppEventBroker overviewEventBroker;

	private final HistoryManager historyManager;

	public OpenStreetMapSampleController(Viewport primaryViewport, Viewport overviewViewport, HandlerManager handlerManager, HandlerManager overviewHandlerManager) {
		this.primaryViewport = primaryViewport;
		this.overviewViewport = overviewViewport;

		this.primaryHandlerManager = handlerManager;
		this.overviewHandlerManager = overviewHandlerManager;

		this.primaryEventBroker = new PrimaryAppEventBroker();
		this.overviewEventBroker = new OverviewAppEventBroker();

		this.historyManager = new HistoryManager();

		handlerManager.addHandler(LoadImageDataEvent.TYPE, this.primaryEventBroker);
		handlerManager.addHandler(SetDomainBoundsEvent.TYPE, this.primaryEventBroker);

		overviewHandlerManager.addHandler(LoadImageDataEvent.TYPE, this.overviewEventBroker);
		overviewHandlerManager.addHandler(SetOverviewDomainBoundsEvent.TYPE, this.overviewEventBroker);

		History.addValueChangeHandler(this.historyManager);
	}

	public void initApp() {
		primaryEventBroker.setViewportBounds();
		overviewEventBroker.setViewportBounds();

		if (!"".equals(History.getToken())) { //has history items
			History.fireCurrentHistoryState();
		} else {
			//Initialize to some defaults
			currentleftBound = 10.55;
			currentrightBound = 11.36;
			currenttopBound = 50.87;
			currentbottomBound = 50.473;

			primaryHandlerManager.fireEvent(new LoadImageDataEvent());
		}

		overviewEventBroker.initializeOverview();
	}

	private double currentleftBound;
	private double currentrightBound;
	private double currenttopBound;
	private double currentbottomBound;

	private class PrimaryAppEventBroker implements LoadImageDataEventHandler, SetDomainBoundsEventHandler {

		public void onLoadImageData(LoadImageDataEvent event) {
			primaryHandlerManager.fireEvent(new SetImageUrlEvent(createUrl(currentleftBound, currentrightBound, currenttopBound, currentbottomBound, getViewportBounds().getAbsWidth().intValue(), getViewportBounds().getAbsHeight().intValue())));

			SetDomainBoundsEvent setDomainBoundsEvent = new SetDomainBoundsEvent(new Bounds(
					currentleftBound,
					currentrightBound,
					currenttopBound,
					currentbottomBound
			), PrimaryAppEventBroker.this);

			primaryHandlerManager.fireEvent(setDomainBoundsEvent);

			//only an example of bounds constraining
			primaryHandlerManager.fireEvent(new SetMaxDomainBoundsEvent(new Bounds(7d, 14d, 47d, 53d)));

			History.newItem("bounds=" + DefaultSetDomainBoundsEventHistoryTokenTransformer.toHistoryTokenValue(setDomainBoundsEvent), false);

			//Telling the OverviewPresenter abouts the clipping section of its overview
			overviewHandlerManager.fireEvent(new SetOverviewDomainBoundsEvent(setDomainBoundsEvent.getBounds(), overviewEventBroker));
		}

		public void onSetDomainBounds(SetDomainBoundsEvent event) {
			currentleftBound = event.getBounds().getLeft();
			currentrightBound = event.getBounds().getRight();
			currenttopBound = event.getBounds().getTop();
			currentbottomBound = event.getBounds().getBottom();
		}

		public void setViewportBounds() {
			primaryHandlerManager.fireEvent(new SetViewportPixelBoundsEvent(getViewportBounds()));
		}

		private Bounds getViewportBounds() {
			return new Bounds(0, primaryViewport.getOffsetWidth(), 0, primaryViewport.getOffsetHeight());
		}
	}

	private class OverviewAppEventBroker implements LoadImageDataEventHandler, SetOverviewDomainBoundsEventHandler {
		private Bounds currentOverviewBounds;

		public void initializeOverview() {
			SetDomainBoundsEvent setDomainBoundsEvent = new SetDomainBoundsEvent(new Bounds(
					10.55,
					11.36,
					50.87,
					50.473
			));

			overviewHandlerManager.fireEvent(new SetImageUrlEvent(createUrl(
					setDomainBoundsEvent.getBounds().getLeft(),
					setDomainBoundsEvent.getBounds().getRight(),
					setDomainBoundsEvent.getBounds().getTop(),
					setDomainBoundsEvent.getBounds().getBottom(),
					getViewportBounds().getAbsWidth().intValue(),
					getViewportBounds().getAbsHeight().intValue())));

			overviewHandlerManager.fireEvent(setDomainBoundsEvent);
		}

		public void onSetOverviewDomainBounds(SetOverviewDomainBoundsEvent event) {
			this.currentOverviewBounds = event.getBounds();
		}

		public void onLoadImageData(LoadImageDataEvent event) {
			//Set the new Bounds of the primary image
			currentleftBound = this.currentOverviewBounds.getLeft();
			currentrightBound = this.currentOverviewBounds.getRight();
			currenttopBound = this.currentOverviewBounds.getTop();
			currentbottomBound = this.currentOverviewBounds.getBottom();

			//and load it
			primaryHandlerManager.fireEvent(new LoadImageDataEvent());
		}

		public void setViewportBounds() {
			overviewHandlerManager.fireEvent(new SetViewportPixelBoundsEvent(getViewportBounds()));
		}

		private Bounds getViewportBounds() {
			return new Bounds(0, overviewViewport.getOffsetWidth(), 0, overviewViewport.getOffsetHeight());
		}
	}

	private String createUrl(double leftBound, double rightBound, double topBound, double bottomBound, int width, int height) {
		return "http://pafciu17.dev.openstreetmap.org/?module=map&bbox=" + leftBound + "," + topBound +"," + rightBound + "," + bottomBound + "&width=" + width + "&height=" + height + "&type=mapnik";
	}

	private class HistoryManager implements ValueChangeHandler<String> {
		public void onValueChange(ValueChangeEvent<String> event) {
			if (event.getValue().contains("bounds=")) {
				String boundsHistoryTokenValue = event.getValue().substring(event.getValue().indexOf("bounds=") + "bounds=".length());

				try {
					primaryHandlerManager.fireEvent(DefaultSetDomainBoundsEventHistoryTokenTransformer.toEvent(boundsHistoryTokenValue));
					primaryHandlerManager.fireEvent(new LoadImageDataEvent());
				} catch (UnparsableHistoryTokenException e) {
					e.printStackTrace();

					Window.alert(e.getMessage());
				}
			}
		}

	}
}
